// Package middleware
// @Author Spume
// @Date 2024-05-09 16:23

package api

import (
	"net/http"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
)

// DefaultHandlerResponse is the default implementation of HandlerResponse.
type DefaultHandlerResponse struct {
	Code    int         `json:"code"    dc:"Error code"`
	Message string      `json:"message" dc:"Error message"`
	Details interface{} `json:"details,omitempty" dc:"Error details"`
	Data    interface{} `json:"data"    dc:"Result data for certain request according API definition"`
}

// MiddlewareHandlerResponse is the default middleware handling handler response object and its error.
func MiddlewareHandlerResponse(r *ghttp.Request) {
	r.Middleware.Next()

	// There's custom buffer content, it then exits current handler.
	if r.Response.BufferLength() > 0 &&
		r.Response.Status != http.StatusInternalServerError &&
		r.Response.Status != http.StatusOK {
		return
	}

	var (
		msg  string = "OK"
		err         = r.GetError()
		res         = r.GetHandlerResponse()
		code        = gerror.Code(err)
	)
	if err != nil {
		if code == CodeNil || code.Code() < 400 {
			code = CodeInternalError
		}

		msg = err.Error()
	} else {
		if r.Response.Status > 0 && r.Response.Status != http.StatusOK {
			msg = http.StatusText(r.Response.Status)
			switch r.Response.Status {
			case http.StatusNotFound:
				code = CodeNotFound
			case http.StatusForbidden:
				code = CodeNotAuthorized
			default:
				code = CodeUnknown
			}
			// It creates error as it can be retrieved by other middlewares.
			err = gerror.NewCode(code, msg)
			r.SetError(err)
		} else {
			code = CodeOK
		}
	}

	if g.IsNil(res) {
		res = struct{}{}
	}
	var details interface{}
	if code.Code() == CodeInternalError.Code() || r.GetQuery("debug").Bool() {
		details = gerror.Stack(err)
	}

	r.Response.SetBuffer(nil)

	r.Response.WriteJson(DefaultHandlerResponse{
		Code:    code.Code(),
		Message: msg,
		Details: details,
		Data:    res,
	})
}
